/******************************************************************************
 * \brief	链路层通信设备模块的操作
 * \note	File format: UTF-8，中文编码：UTF-8
 * \author	将狼才鲸
 * \date	2023-03-25
 ******************************************************************************/

#ifndef _SCP_DEVS_H_
#define _SCP_DEVS_H_

/*********************************** 头文件 ***********************************/
#include "scp_protocol.h"
#include <stdint.h>	/* uint8_t... */
#include <stdbool.h>	/* bool true false */

/*********************************** 宏定义 ***********************************/
/**
 * \brief	传输设备类型
 * \details	在某个传输设备上首次进行通信时，需要调用scp_init创建通信连接
 */
#define SCP_DEVTYPE_SOCKET		(1u << 0)	/* 本地网络套接字 */
#define SCP_DEVTYPE_SHM			(1u << 1)	/* 共享内存，模拟寄存器地址 */
#define SCP_DEVTYPE_FIFO		(1u << 2)	/* 命名管道 */
#define SCP_DEVTYPE_MSGQUEUE_A	(1u << 3)	/* 消息队列，客户端使用 */
#define SCP_DEVTYPE_MSGQUEUE_B	(1u << 4)	/* 消息队列，服务器端使用 */
#define SCP_DEVTYPE_ANY			(0xFFFF)

/* 设备读取的数据包类型，每个消息发送都要经历这几个阶段 */
#define RWMODE_REQUEST          (1u << 0)
#define RWMODE_RESPOND          (1u << 1)
#define RWMODE_START            (1u << 2)
#define RWMODE_FINISH           (1u << 3)

/********************************** 类型定义 **********************************/
/**
 * \brief	设备句柄
 * \details	该结构体占用48~52字节，需要小于QBUF_GROUP_TMPBUF缓存的512字节
 */
typedef struct _scp_dev {
	qbuf_t *qbuf;
	int32_t dev_type;	/* 通信设备类型：SCP_DEVTYPE_SOCKET... */
	
	uint32_t hwaddr;	/* 用于核间通信或进程间通信直接交换内存地址，省掉内存拷贝的时间 */
	uint32_t max_size;	/* 支持的最大数据长度 */
	
	uint8_t priv_data[32];	/* 设备私有的结构体数据，如scpdev_socket_t数据 */
} scp_dev_t;

/********************************** 接口函数 **********************************/
/**
 * \brief	从通用设备结构体中获取到具体设备私有的结构体
 * \details	每个具体的通信设备里私有的结构体都不同
 * \param	pdev:	设备结构体
 */
extern uint8_t *scpdev_pri(scp_dev_t *pdev);

// extern scp_dev_t *scpdev_from_pri(void *pri);

/**
 * \brief 申请通信需要的数据空间
 * \param	priv_len:	特定通信设备需要的额外数据空间，如sizeof(scpdev_socket_t)
 */
extern scp_dev_t *scpdev_new(unsigned zl);

/**
 * \brief	当前设备结构体是允许的设备
 * \param	pdev:	设备结构体
 * \param	type:	允许的设备类型
 */
extern bool scpdev_valid(scp_dev_t *pdev, int type);

/**
 * \brief	释放设备句柄
 */
extern bool scpdev_free(scp_dev_t *pdev);

/**
 * \brief	初始化通信设备
 * \param	hwaddr:	如果是多核通信，可以使用内存地址传递数据
 * \param	type:	指定通信设备，如串口、网络、核间通信、进程间通信等
 */
extern scp_dev_t *scpdevs_init(uint32_t hwaddr, int type);

/**
 * \brief	释放设备缓存
*/
extern int scpdevs_exit(scp_dev_t *pdev);

/**
 * \brief	准备好设备，清空设备缓存
 */
extern int scpdevs_start(scp_dev_t *pdev);

// extern int scpdevs_stop(scp_dev_t *pdev);

/**
 * \brief	发送消息
 * \param	seg:	段句柄
 * \param	wmode:	单次消息发送的某个阶段：RWMODE_START、RWMODE_FINISH、RWMODE_REQUEST、RWMODE_RESPOND
 */
extern int scpdevs_send(segment_t *seg, uint8_t wmode);

/**
 * \brief	接收数据包；有接收队列，从中获取最早到达的包
 * \details	轮询的读消息，一次轮询不一定读到完整的包，可能多次轮询后才能收满包
 * \param	pdev:	设备句柄
 * \param	rmode:	读数据时的步骤：RWMODE_REQUEST...
 * \return	已收完则返回数据包，或者未收完或未收到返回NULL
 */
extern segment_t *scpdevs_read(scp_dev_t *pdev, uint8_t rmode);

#endif /* _SCP_DEVS_H_ */

/*********************************** 文件尾 ***********************************/
